﻿#include <Sys\RenderUnit\SysRenderDatagram\GROUPRD.HPP>

#define CGroup_ClassID L"556429D798944e77932A3A2982596DBB"

using namespace CxxlMan;
using namespace Cxxl3D;

cxxlObject *cxxlFASTCALL New_CGroupRD(void *);
cxxlPreserve2 *cxxlFASTCALL Regenera_CGroupRD(const wchar_t *ClassID);


class CGroupRD:public IGroupRD
{
  UNICODE_String m_Name;
  P2Smart_Set<IRenderDatagram> m_IRenderDatagram_Set;
  Smart_Ptr<cxxlList<IRenderDatagram> > m_IRenderDatagram_List;
  bool m_isCrush;

  // 記錄 Group 物件，採用 Name 為 key，為配合 P2Smart_Set 可重複放入，所以 key 值可重複
  class tagGroupTree:public cxxlAVL_Tree<IGroupRD, const UNICODE_String, false>
  {
    // 排序檢測，延伸類別須實作此函數
    // 要讓 O_Key 鍵值所代表的物件排在 左 回答 true，否則 false
    bool cxxlFASTCALL isLeftAt(const UNICODE_String O_Key,const UNICODE_String addKey) const
    {
      return O_Key <= addKey;
    } 

    // 這函數用來決定在容器中 O_Key 鍵值所代表的物件，是不是 findKey 所要尋找的 
    // 是 回答 true，否則 false，延伸類別須實作此函數
    bool cxxlFASTCALL isEqual(const UNICODE_String O_Key, const UNICODE_String findKey)  const
    {
      return O_Key == findKey;
    } 

  public:
    tagGroupTree(ISpirit *spirit = Spirit_Easy)  // Constructor
     :cxxlObject(spirit)
    {
    }
  };

  Smart_Ptr<tagGroupTree> m_GroupTree_Ptr;

  // 若是 class IGroupRD 會回覆 true 
  virtual bool cxxlFASTCALL isGroup() const
  {
    return true;
  }

  // 加入一個 IRenderDatagram 物件
  virtual bool cxxlFASTCALL Add(const CxxlMan::Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg)
  {
    CriticalSecHandle AutoCSH(csPreserve);

    if(m_isCrush)
      return false;

    m_IRenderDatagram_Set.Add(IRenderDatagram_Arg);
    m_IRenderDatagram_List->Push_Back(IRenderDatagram_Arg);

    if(IRenderDatagram_Arg->isGroup())
    {
      Smart_Ptr<IGroupRD> IGroupRD_Ptr = Smart_Cast<IGroupRD>(IRenderDatagram_Arg);
      m_GroupTree_Ptr->Add(IGroupRD_Ptr, IGroupRD_Ptr->GetName());
    }
    
    return true;
  }

  // 移除一個 IRenderDatagram 物件
  virtual bool cxxlFASTCALL Del(const CxxlMan::Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg)
  {
    CriticalSecHandle AutoCSH(csPreserve);

    if(m_isCrush)
      return false;

    m_IRenderDatagram_Set.Delete(IRenderDatagram_Arg);
    m_IRenderDatagram_List = m_IRenderDatagram_Set.GetList();
    if(IRenderDatagram_Arg->isGroup())
    {
      Smart_Ptr<IGroupRD> IGroupRD_Ptr = Smart_Cast<IGroupRD>(IRenderDatagram_Arg);
      m_GroupTree_Ptr->Delete(IGroupRD_Ptr->GetName());
    }
    
    return true;
  }

  // 清空
  virtual bool cxxlFASTCALL Clear()
  {
    CriticalSecHandle AutoCSH(csPreserve);

    if(m_isCrush)
      return false;

    m_IRenderDatagram_Set.Destroy();
    m_GroupTree_Ptr->ClearAll();
    m_IRenderDatagram_List->ClearAll();

    return true;
  }


  // 取得指定名稱的子 IGroupRD
  virtual CxxlMan::Smart_Ptr<IGroupRD> cxxlFASTCALL GetChdGroup(const CxxlMan::UNICODE_String &Name)
  {
    CriticalSecHandle AutoCSH(csPreserve);

    if(m_isCrush)
      return NULL;

    return m_GroupTree_Ptr->GetObj(Name);
  }

  // 取得名稱
  virtual CxxlMan::UNICODE_String cxxlFASTCALL GetName()
  {
    CriticalSecHandle AutoCSH(csPreserve);
    return m_Name;
  }

  // 取得 IRenderDatagram 列表
  virtual Smart_Ptr<CxxlMan::cxxlList<IRenderDatagram> > cxxlFASTCALL GetList()
  {
    CriticalSecHandle AutoCSH(csPreserve);
    return m_IRenderDatagram_List;
  }

  // 取得 IRenderDatagram 列表
  virtual CxxlMan::Smart_Ptr<cxxlList<IRenderDatagram> > cxxlFASTCALL CopyList()
  {
    CriticalSecHandle AutoCSH(csPreserve);
    return m_IRenderDatagram_List->Clone();
  }


  // 清除除了已存在的 IRenderDatagram 列表外的所有資料，之後就不能再執行增刪和永續儲存的功能
  virtual void cxxlFASTCALL Crush()
  {
    csPreserve.Enter();

    m_isCrush = true;

    m_IRenderDatagram_Set.Destroy();
    m_GroupTree_Ptr.Destroy();

    csPreserve.Leave();
  }

  // 清除除了已存在的 IRenderDatagram 列表外的所有資料，包含子孫 IGroupRD，之後就不能再執行增刪和永續儲存的功能
  virtual void cxxlFASTCALL CrushAll()
  {
    csPreserve.Enter();

    m_isCrush = true;

    m_IRenderDatagram_Set.Destroy();

    Smart_Ptr<cxxlList<IGroupRD> > IGroupRD_List = m_GroupTree_Ptr->cxxlList_Create();
    unsigned long Count = IGroupRD_List->GetCount();
    IGroupRD_List->ResetPT(toHead);
    for(Smart_Ptr<IGroupRD> IGroupRD_Ptr = (*IGroupRD_List)++; Count; --Count,IGroupRD_Ptr = (*IGroupRD_List)++)
      IGroupRD_Ptr->CrushAll();
    
    m_GroupTree_Ptr.Destroy();

    csPreserve.Leave();
  }


protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IGroupRD::Ref(F))
    {
      if(m_isCrush)
        return false;


      LoadFilter *pLoadFilter = dynamic_cast<LoadFilter*>(F);
      if(pLoadFilter == NULL) // 表示 F 是 SaveFilter
      {        
        F->Ref((const wchar_t*)m_Name,m_Name.StrLength()+1,L"CGroupRD.Name" );
      }
      else
      {
        wchar_t *tmpName = NULL;
        if(pLoadFilter->LoadRef((const wchar_t **)(void **)&tmpName, L"CGroupRD.Name") == false)
          return false;

        if(pLoadFilter->isChk() != false) // 讀取階段
        {
          m_Name = tmpName;
          delete [] tmpName;

          m_GroupTree_Ptr->ClearAll();
          m_IRenderDatagram_List = m_IRenderDatagram_Set.GetList();

          m_IRenderDatagram_List->ResetPT(toHead);
          unsigned long Count = m_IRenderDatagram_List->GetCount();
          for(Smart_Ptr<IRenderDatagram> IRenderDatagram_Ptr = (*m_IRenderDatagram_List)++; Count--; IRenderDatagram_Ptr = (*m_IRenderDatagram_List)++)
          {
            if(IRenderDatagram_Ptr->isGroup())
            {
              Smart_Ptr<IGroupRD> IGroupRD_Ptr = Smart_Cast<IGroupRD>(IRenderDatagram_Ptr);
              m_GroupTree_Ptr->Add(IGroupRD_Ptr, IGroupRD_Ptr->GetName());
            }
          }
          
        }
      }      

      return true;
    }      
    else
      return false;
  }

   

public:
  // Constructor
  CGroupRD(const UNICODE_String &Name)
    :cxxlObject(CxxlMan::Spirit_Easy),    
    cxxlPreserve2(CGroup_ClassID), // 在建構時指定 ClassID
    m_Name(Name),
    m_IRenderDatagram_Set(this,L"CGroupRD.IRenderDatagram_Set"),
    m_IRenderDatagram_List(new cxxlList<IRenderDatagram>,this),
    m_GroupTree_Ptr(new tagGroupTree, this)
  {
    m_isCrush = false;
  }

  // Destructor
  ~CGroupRD(){}

  friend cxxlObject *cxxlFASTCALL New_CGroupRD(void *);
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CGroupRD(const wchar_t *ClassID);

};

cxxlObject *cxxlFASTCALL New_CGroupRD(void *Arg)
{
  return new CGroupRD(*(const UNICODE_String*)Arg);
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CGroupRD(const wchar_t *ClassID)
{
  if(wcscmp(CGroup_ClassID, ClassID) == 0)
    return new CGroupRD((wchar_t*)NULL);
  else
    return NULL;

}
